package com.yfbao.horizon.utils;

import com.yfbao.horizon.common.StatDto;
import com.yfbao.horizon.model.SingleResponse;
import com.yfbao.horizon.model.TestUser;
import com.yfbao.horizon.model.TestVo;
import com.yfbao.horizon.service.JarLoaderUtil;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class Reflact {

    private static Long length = 0L;

    public static void main(String[] args) throws Exception {

//测试方法
        List<TestVo> rooms = new ArrayList<TestVo>();
        rooms.add(new TestVo());
        rooms.add(new TestVo());
        TestUser u = new TestUser("zhangsan", 18, rooms);

        List<Method> metohdsOutObjectMethods = getMetohdsOutObjectMethods(u.getClass());
        System.out.println("metohdsOutObjectMethods:"+metohdsOutObjectMethods.size());
//        doWithR(u);
        Set<Class<?>> classSet = ClassHelper.getClassSet();
//        String jarFile ="C:\\Users\\byf78\\Desktop\\日志分析\\接口流量测算\\ctp-user-biz-2.7.0-TEST-SNAPSHOT.jar";
//        Class<?> aClass = JarLoaderUtil.getClass("com.seeyon.ctp.user.appservice.CtpLockedIpAppService");
//        if(aClass !=null){
//            System.out.println("找到了类："+aClass.getName());
//        }
        System.out.println("类的数量:"+classSet.size());
        System.out.println("-----------------------------------");
//        doWithList(u.getClass());
//        getByMethod(u.getClass());
//        getByMethods(u.getClass());
        getMethodResLength(u.getClass());

//        SingleResponse<TestVo> from2 = SingleResponse.from(new TestVo());
//        doSingleResponse(from2.getClass());

//        SingleResponse<List<TestVo>> from = SingleResponse.from(rooms);
//        doSingleResponse(from.getClass());
        System.out.println("length:" + length);
    }

    private static List<Method> getMetohdsOutObjectMethods(Class<?> clazz){
        List<Method> objectMetohds = getObjectMethods(clazz);
        List<Method> arrayList = getObjectMethods(Object.class);
        Iterator<Method> iterator = objectMetohds.iterator();
        loop: while (iterator.hasNext()){
            Method next = iterator.next();
            for (Method method : arrayList) {
                if(method.getName().equals(next.getName())){
                    iterator.remove();
                    continue loop;
                }
            }
        }
        return objectMetohds;
    }
    private static List<Method> getObjectMethods(Class<?> clazz){
        Method[] declaredMethods = clazz.getDeclaredMethods();
        List<Method> arrayList = new ArrayList<>();
        for (Method declaredMethod : declaredMethods) {
            arrayList.add(declaredMethod);
        }
        return arrayList;
    }

    public static void getMethodResLength(Class<?> aClass) throws Exception {
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println("do  method-name:"+method.getName());
            long methodResLength = ScanClass.getMethodResLength(method);
            System.out.println("method-name:"+method.getName()+",length:"+methodResLength);
        }
    }

    public static void getByMethods(Class<?> aClass) throws Exception {
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            Type genericReturnType = method.getGenericReturnType();
            if(genericReturnType.getTypeName().equalsIgnoreCase("void")){
                continue;
            }
            if (genericReturnType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
                //获得Demo1<String>，<>中的实际类型参数
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    innnerCheck(actualTypeArgument);
                }
                //获得参数类型

                continue;
            }
//            Class<?> clazz = (Class<?>) genericReturnType;
//            System.out.println(clazz.getName());

            System.out.println(genericReturnType);
        }

    }

    private static boolean innnerCheck(Type actualTypeArgument) throws Exception {
        if (actualTypeArgument instanceof ParameterizedType) {
            if(actualTypeArgument instanceof ParameterizedTypeImpl){
                ParameterizedTypeImpl actualType = (ParameterizedTypeImpl) actualTypeArgument;
                if(actualType.getRawType().isAssignableFrom(List.class)){
                    //TODO： list 处理
                    Type[] listActualTypeArguments = actualType.getActualTypeArguments();
                    for (Type listActualTypeArgument : listActualTypeArguments) {
                        System.out.println("list:"+listActualTypeArgument.getTypeName());
                        //todo: 递归循环调用获取对象长度
                        innnerCheck(listActualTypeArgument);
                    }
                    return true;
                }
                if(actualType.getRawType().isAssignableFrom(Map.class)){
                    //TODO  MAP的处理方式
                    System.out.println("map:"+actualType.getTypeName());
                    Type[] actualTypeArguments = actualType.getActualTypeArguments();
                    for (Type typeArgument : actualTypeArguments) {
                        innnerCheck(typeArgument);
                    }
                    return true;
                }
            }
            ParameterizedType pt = (ParameterizedType) actualTypeArgument;
            //得到泛型里的class类型对象。
            Type[] ptActualTypeArguments = pt.getActualTypeArguments();
            for (Type ptActualTypeArgument : ptActualTypeArguments) {
                System.out.println(ptActualTypeArgument.getTypeName());
                innnerCheck(ptActualTypeArgument);
                continue;
            }
        }
        Class<?> clazz = null;
        try {
            clazz = (Class<?>) actualTypeArgument;
        }catch (Throwable t){
            System.out.println("不识别的类型："+actualTypeArgument.getTypeName());
            return false;
        }
        //TODO: 计算类中属性长度
        doWithList(clazz);
        System.out.println(clazz.getName());
        return true;
    }



    public static void getByMethod(Class<?> aClass) {
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            if (method.getName().equalsIgnoreCase("test1")) {
                Type genericReturnType = method.getGenericReturnType();
                if (genericReturnType instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
                    //获得Demo1<String>，<>中的实际类型参数
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    //获得参数类型
                    Class<?> clazz = (Class<?>) actualTypeArguments[0];
                    System.out.println(clazz.getName());
                    continue;
                }
                System.out.println(genericReturnType);
            }

            if (method.getName().equalsIgnoreCase("test2")) {
                Type genericReturnType = method.getGenericReturnType();
                if (genericReturnType instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
                    //获得Demo1<String>，<>中的实际类型参数
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    Type actualTypeArgument = actualTypeArguments[0];
                    if (actualTypeArgument instanceof ParameterizedType) {
//                        ((ParameterizedTypeImpl) actualTypeArgument).getActualTypeArguments()
                        ParameterizedType pt = (ParameterizedType) actualTypeArgument;

                        //得到泛型里的class类型对象。
                        Class genericClazz = (Class) pt.getActualTypeArguments()[0];
                        System.out.println(genericClazz.getName());
                        continue;
                    }
                    //获得参数类型
                }
                System.out.println(genericReturnType);
            }
        }
    }

    public static void check(Object obj) throws Exception {
        Class<?> aClass = obj.getClass();
        if (List.class.isAssignableFrom(aClass)) {
            doWithList(aClass);
        }
        Field[] fields = aClass.getDeclaredFields();
        for (Field f : fields) {
            if (!f.isAccessible()) {
                f.setAccessible(true);//赋权使用，不然private类型是没法操做的
            }
//            doWithR(f);

        }
    }


    static void doSingleResponse(Class<?> aClass) throws NoSuchFieldException {

        if (aClass.isAssignableFrom(SingleResponse.class)) {

            Type genericSuperclass = aClass.getGenericSuperclass();

            Type genericSuperclass1 = genericSuperclass.getClass().getGenericSuperclass();
            //判断父类是不是参数化的类型，如果是强转成ParameterizedType
            if (genericSuperclass1 instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass1;
                //获得Demo1<String>，<>中的实际类型参数
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                //获得参数类型
                Class<?> clazz = (Class<?>) actualTypeArguments[0];
                System.out.println(clazz);
            }

            Field data = aClass.getDeclaredField("data");
            Class<?> type = data.getType();
            Type genericSuperclassData = type.getGenericSuperclass();
            //判断父类是不是参数化的类型，如果是强转成ParameterizedType
            if (genericSuperclassData instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericSuperclassData;
                //获得Demo1<String>，<>中的实际类型参数
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                //获得参数类型
                Class<?> clazz = (Class<?>) actualTypeArguments[0];
                System.out.println(clazz);
            }
            return;
        }
    }

    static void doWithList(Class<?> aClass) throws Exception {

        Field[] fields = aClass.getDeclaredFields();//获取字段信息
//        Field fields = aClass.getDeclareFields();//获取字段信息
        for (Field f : fields) {
            Class<?> fieldClazz = f.getType();//获取f的类
            if (fieldClazz.isPrimitive()) {
                doPrimitaiveCalc(fieldClazz);
                System.out.println(fieldClazz.getName() + ",length:" + length);
                continue;  //判断是否为基本类型
            }
            if (fieldClazz.isAssignableFrom(List.class)) {//判断fc是否和List相同或者其父类
                Type fc = f.getGenericType(); //如果是List类型，得到其Generic的类型
                if (fc instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) fc;
                    //得到泛型里的class类型对象。
                    Class genericClazz = (Class) pt.getActualTypeArguments()[0];
                    System.out.println(genericClazz.getName());
                    doWithList(genericClazz);
                    continue;
                }
            }
//            if(f.getName().equalsIgnoreCase("data") || f.getName().equalsIgnoreCase("content")){
//                //获得带有泛型的父类
//                Type genericSuperclass = fieldClazz.getGenericSuperclass();
//                //判断父类是不是参数化的类型，如果是强转成ParameterizedType
//                if (genericSuperclass instanceof ParameterizedType){
//                    ParameterizedType parameterizedType = (ParameterizedType)genericSuperclass;
//                    //获得Demo1<String>，<>中的实际类型参数
//                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//                    //获得参数类型
//                    Class<?> clazz = (Class<?>)actualTypeArguments[0];
//                    System.out.println(clazz);
//                    doWithList(clazz);
//                    continue;
//                }
//            }
            if (fieldClazz.isAssignableFrom(Object.class)) {
                continue;
            }
            if (!doCalc(fieldClazz)) {
                doWithList(fieldClazz);
            }
        }
    }

    /**
     * * @see     java.lang.Boolean#TYPE 1/4
     * * @see     java.lang.Character#TYPE 2
     * * @see     java.lang.Byte#TYPE 1
     * * @see     java.lang.Short#TYPE  2
     * * @see     java.lang.Integer#TYPE   4
     * * @see     java.lang.Long#TYPE 8
     * * @see     java.lang.Float#TYPE 4
     * * @see     java.lang.Double#TYPE 8
     * * @see     java.lang.Void#TYPE 0
     *
     * @param aClass
     */
    static boolean doCalc(Class<?> aClass) {
        if (aClass.isAssignableFrom(Boolean.class)) {
            length = length + 4 + 4;
            return true;
        } else if (aClass.isAssignableFrom(Character.class)) {
            length = length + 2 + 4;
            return true;
        } else if (aClass.isAssignableFrom(Byte.class)) {
            length = length + 1 + 4;
            return true;
        } else if (aClass.isAssignableFrom(Short.class)) {
            length = length + 2 + 4;
            return true;
        } else if (aClass.isAssignableFrom(Integer.class)) {
            length = length + 4 + 4;
            return true;
        } else if (aClass.isAssignableFrom(Long.class)) {
            length = length + 8 + 4;
            return true;
        } else if (aClass.isAssignableFrom(Float.class)) {
            length = length + 4 + 4;
            return true;
        } else if (aClass.isAssignableFrom(Double.class)) {
            length = length + 8 + 4;
            return true;
        } else if (aClass.isAssignableFrom(String.class)) {
            length = length + 50 + 4;
            return true;
        }
        return false;
    }

    static void doPrimitaiveCalc(Class<?> aClass) {
        if (aClass.isAssignableFrom(boolean.class)) {
            length = length + 4;
            return;
        } else if (aClass.isAssignableFrom(char.class)) {
            length = length + 2;
            return;
        } else if (aClass.isAssignableFrom(byte.class)) {
            length = length + 1;
            return;
        } else if (aClass.isAssignableFrom(short.class)) {
            length = length + 2;
            return;
        } else if (aClass.isAssignableFrom(int.class)) {
            length = length + 4;
            return;
        } else if (aClass.isAssignableFrom(long.class)) {
            length = length + 8;
            return;
        } else if (aClass.isAssignableFrom(float.class)) {
            length = length + 4;
            return;
        } else if (aClass.isAssignableFrom(double.class)) {
            length = length + 8;
            return;
        }
        System.out.println("unknow Primitaive:" + aClass.getName());
    }


    static void doWithR(Object obj) throws Exception {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field f : fields) {
            if (!f.isAccessible()) {
                f.setAccessible(true);//赋权使用，不然private类型是没法操做的
            }
            if (List.class.isAssignableFrom(f.getType())) {//判断是否为list
                Type t = f.getGenericType();
                if (t instanceof ParameterizedType) {
                    //ParameterizedType pt = (ParameterizedType)t;
                    //Class clz = (Class)pt.getActualTypeArguments()[0];
                    Class clazz = f.get(obj).getClass();//获取对象list属性的class
                    Method m = clazz.getDeclaredMethod("size");//获取list属性的size方法
                    int size = (Integer) m.invoke(f.get(obj));//调用size方法
                    for (int i = 0; i < size; i++) {//根据size大小循环
                        Method getM = clazz.getDeclaredMethod("get", int.class);//获取list属性的get方法
                        //System.out.println(getM);
                        Object u = getM.invoke(f.get(obj), i);//调用get方法获取list中的对象
                        doWithR(u);//若list中还有list能够递归调用
                        //测试是否能够获取到list中对象的属性的值
                        Field[] uf = u.getClass().getDeclaredFields();
                        for (Field fu : uf) {
                            if (!fu.isAccessible())
                                fu.setAccessible(true);
                            System.out.println(fu.get(u));
                        }
                    }
                }
            }
        }
    }
}
